'''
Copyright 2010 Indra Bagus <indra.bagus@gmail.com> 
    
Licensed under the Apache License, Version 2.0 (the "License"); 
you may not use this file except in compliance with the License. 
You may obtain a copy of the License at 

    http://www.apache.org/licenses/LICENSE-2.0 
    
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. 
'''



import itertools
import array

def CalculateHCS(arr_pdu = '') :
    crc = 0
    for i in arr_pdu :
        crc ^= ord(i)
        for j in xrange(8):
            if(crc & 0x80):
                crc = (crc<<1) ^ 0x07
            else:
                crc = (crc << 1 )
    return crc & 0xff


def CalculateCRC32OFDM(arrayPdu) :
    crc = 0xFFFFFFFF
    for i in arrayPdu :
        counter = 0
        while counter < 8 :
            if ((crc ^ i) & 0x01) :
                crc = (crc >> 1) ^ 0xEDB88320
            else :
                crc = (crc >> 1)
            i = i >> 1
            counter = counter + 1
        
    return crc^0xFFFFFFFF



def CalculateCRC32OFDMA(stringpdu):
    remainder = 0xFFFFFFFF
    for i in stringpdu:
        temp = ((remainder >> 24) ^ ord(i)) & 0xFF
        crctemp = temp << 24
        counter = 0
        while counter < 8 :
            if (crctemp & 0x80000000):
                crctemp = (crctemp << 1 ) ^ 0x04C11DB7
            else:
                crctemp = crctemp << 1
            counter += 1
        
        remainder = (remainder << 8) ^ crctemp
        
    return (~remainder)&0xFFFFFFFF



def CalculateCRC32OFDMAReceiver(stringpdu):
    remainder = 0xFFFFFFFF
    for i in stringpdu:
        temp = ((remainder >> 24) ^ ord(i)) & 0xFF
        crctemp = temp << 24
        counter = 0
        while counter < 8 :
            if (crctemp & 0x80000000):
                crctemp = (crctemp << 1 ) ^ 0x04C11DB7
            else:
                crctemp = crctemp << 1
            counter += 1
        
        remainder = (remainder << 8) ^ crctemp
        
    return (remainder)&0xFFFFFFFF


def DumpBuffString(strdata=str(),byte_perline = 16) :
    '''
    Dump string buffer
    @param strdata: String that will be dumped 
    @param byte_perline: Number of byte perline
    '''
    strarr = array.array('B',strdata)
    return DumpBuffList(strarr,byte_perline)
    

    
def DumpBuffList(arrdata,byte_perline = 16 ) :
    idx = 0                                                    
    length = len(arrdata)
    stroutput = '| '                         
    for i in arrdata :                                         
        idx+=1                                                 
        stroutput += '%2.2X' % i                             
        if(idx == length) :                                    
            remindidx = idx % byte_perline
            if(remindidx != 0x00):
                remindidx = byte_perline-remindidx
                
            while(remindidx > 0):
                stroutput += '   '
                remindidx -= 1
            stroutput += ' |'
            break
                                                      
        stroutput += ' '                                       
        if (idx % byte_perline == 0) :                         
            stroutput += '| \n| '                              
                                                               
    return stroutput



def IntegerToListInteger(int_val, num_element=4, element_size=32):
    '''
        @param int_val      an arbitrary length Python integer to be split up.
                            Network byte order is assumed. Raises an IndexError if width of
                            integer (in bits) exceeds word_size * num_words.
        @param num_element  Number of words expected in return value tuple.
        @param word_size    Size/width of individual words (in bits).
        @return             A list of fixed width words based on provided parameters.
    '''
    max_int = 2 ** (element_size*num_element) - 1
    max_word_size = 2 ** element_size - 1
    if not 0 <= int_val <= max_int:
        raise IndexError('integer %r is out of bounds!' % hex(int_val))
    words = []
    for _ in range(num_element):
        word = int_val & max_word_size
        words.append(int(word))
        int_val >>= element_size
    words.reverse()
    return words



class BitStream(object):
    def __init__(self, s='', big_endian=True):
        self.be         = big_endian
        self.buf        = 0L
        self.bufbits    = 0
        self.getbyte    = itertools.imap(ord, s).next

        
    def read(self, nb=0, signed=False):
        try:
            while self.bufbits < nb:
                if self.be:
                    self.buf = (self.buf<<8) | self.getbyte()
                else:
                    self.buf |= (long(self.getbyte())<<self.bufbits) # put at top                    
                self.bufbits+=8
        except StopIteration: # no more getbyte data
            raise EOFError, 'Failed to read %s bits from available %s.'%(nb, self.bufbits)
        
        self.bufbits -= nb
        if self.be:
            ret = self.buf>>self.bufbits
            self.buf &= ((1L<<self.bufbits)-1)
        else:
            ret = self.buf & ((1L<<nb)-1)
            self.buf >>= nb


        if signed:
            signbit = 1L<<(nb-1)
            if signbit & ret:
                ret = ret - signbit -signbit
                if -2**31 <= ret < 2**31: return int(ret)
        return ret #, nb
    
    
    def __getslice__(self,i,j):
        pass
    
    
    def __setslice__(self,i,j,sequence):
        pass
    
    
    def __delslice__(self,i,j):
        pass
    
    
    def __len__(self):
        pass
    
    
    
    
    